<html>
    <head>
        <title>概览</title>
    </head>
    <body>
        <script>
            // BLOB 存储

                    /*
                        在应用程序中存储文件内容，并根据需要读取这些文件内容是典型的需求。

                        不仅仅是文件，你可能还需要将各种类型的"大型二进制对象"，又称为 BLOB 保存到"存储"中。

                        BLOB是一个典型的"字节数组"。 有多个地方可以存储BLOB项； 可以选择存储在本地文件系统、共享数据库 或者  Azure(的云计算平台 Microsoft Azure) Blob存储中
                    
                        
                        ABP 提供了使用BLOB的抽象，并提供了一些你可以轻松集成到的"预构建存储提供程序"。
                        拥有这样的抽象又一些好处：

                                ①、你可以通过几行配置轻松地将集成到你最喜欢的BLOB存储中。

                                ②、然后，你可以轻松更改你的BLOB存储，而无需更改你的应用程序代码。

                                ③、如果你想创建可重用的应用程序模块，你不需要假设BLOB是如何存储的。
                    

                        ABP BLOB存储系统还兼容其他ABP功能，例如多租户
                    */


                    /*
                        一、BLOB存储提供程序  BLOB Storage Providers

                                ABP已经有以下存储提供程序实现：

                                    1、File System：将BLOB作为标准文件存储在本地文件系统的文件夹中。

                                    2、Database：将BLOB存储在数据库中。

                                    3、Azure：将BLOB存储在Azure BLOB存储上。

                                    4、阿里云：将BLOB存储在阿里云存储服务上。

                                    5、Minio：将BLOB存储在MinIO对象存储上。

                                    6、Aws：将BLOB存储在Amazon Simple Storage Service上。

                                    7、Google：将BLOB存储在Google Cloud Storage上。

                                届时将实现更多提供程序。你可以为你最喜欢的提供程序请求或自己创建它并为ABP贡献。

                                在容器系统的帮助下，多个提供者可以一起使用，其中每个容器可以使用不同的提供者。

                                除非你配置存储提供程序，否则BLOB存储系统无法工作。有关存储提供程序配置，请参阅链接文档。
                    */


                    /*
                        二、安装

                                "Volo. Abp.BlosStow"  是定义BLOB存储服务的主包。

                                你可以使用此包来使用BLOB存储系统，而无需依赖特定的存储提供程序。

                                1、使用ABP CLI 将此包添加到你的项目：

                                        如果你尚未安装ABP CLI，请安装它。

                                        在.csproj文件目录中打开一个命令行（终端），你要添加Volo.Abp.BlobStoring包。

                                        运行"abp add-package Volo.Abp.BlobStoring "命令。


                                2、手动安装：

                                        如果你想手动执行此操作，请将Voo. Abp.BlosStowNuGet包安装到你的项目中，
                                        
                                        并将[DependsOn(typeof(AbpBlobStoringModule))]添加到项目内的ABP模块类中。
                    */

                    /*
                        三、IBlobContainer 容器

                                IBlobContainer 是"存储" 和 "读取" BLOB 的主接口。

                                你的应用程序可能有多个容器，每个容器都可以单独配置。
                                
                                但是，有一个"默认容器"可以简单地通过注入IBlobContainer服务来使用。

                                eg：简单地保存和读取命名BLOB的字节

                                            using System.Threading.Tasks;
                                            using Volo.Abp.BlobStoring;
                                            using Volo.Abp.DependencyInjection;

                                            namespace AbpDemo
                                            {
                                                public class MyService : ITransientDependency
                                                {
                                                    private readonly IBlobContainer _blobContainer;

                                                    public MyService(IBlobContainer blobContainer)
                                                    {
                                                        _blobContainer = blobContainer;  // 注入IBlobContainer服务
                                                    }

                                                    // 保存BLOB对象到默认容器中
                                                    public async Task SaveBytesAsync(byte[] bytes)
                                                    {
                                                        await _blobContainer.SaveAsync("my-blob-1", bytes);
                                                    }
                                                    
                                                    // 从默认容器中读取BLOB对象
                                                    public async Task<byte[]> GetBytesAsync()
                                                    {
                                                        return await _blobContainer.GetAllBytesOrNullAsync("my-blob-1"); // 获取指定名称的BLOB对象字节数组，如果找不到则返回null
                                                    }
                                                }
                                            }

                                        此服务使用my-blob-1名称保存给定字节，然后获取先前保存的同名字节。

                                    BLOB是一个命名对象，每个BLOB都应该有一个唯一的名称，它是一个任意字符串。
                                        
                                    IBlobContainer 可以使用Stream 和 byte[] 对象，这将在下一节中详细介绍。


                                1、保存BLOB
                                        SaveAsync 方法用于保存新的BLOM或替换现有的BLOB。

                                        它可以默认保存一个Stream，但有一个快捷扩展方法来保存字节数组。

                                        SaveAsync 方法，可以获取以下参数：

                                                ①、name (string): BLOB的唯一名称。

                                                ②、stream (Stream) 或者 bytes (byte[]): 要保存的BLOB内容。

                                                ③、overrideExeption (bool): 如果BLOB内容已经存在，则设置true可以替换它。
                                                                            默认为false，如果容器中已经有个同名的BLOB，则抛出 BlobAlreadyExistsException。


                                2、读取BLOB
                                    
                                        ①、GetAsync：仅获取一个BLOB名称并返回一个可用于读取BLOB内容的Stream对象。
                                                     使用后始终释放流。
                                                     如果找不到具有给定名称的BLOB，此方法会引发异常。

                                        ②、GetOrNullAsync：与GetAsync方法相反，如果没有找到具有给定名称的BLOB，则此方法返回null。

                                        ③、GetAllBytesAsync：返回byte[]而不是Stream。如果找不到具有给定名称的BLOB，仍然会引发异常。

                                        ④、GetAllBytesOrNullAsync：与GetAllBytesAsync方法相反，如果没有找到具有给定名称的BLOB，则此方法返回null。


                                3、删除BLOB
                                                        
                                        DeleteAsync，方法获取BLOB名称并删除BLOB数据。如果未找到给定的BLOB，它不会引发任何异常。
                                                    相反，如果你关心它，它会返回一个bool，指示BLOB是否已实际删除。
                                                     
                                4、其他方法

                                        ExistsAsync方法只是检查容器中是否有具有给定名称的BLOB。


                                5、 关于命名BLOB

                                        没有命名BLOB的规则。

                                        BLOB名称只是每个容器（和每个租户）唯一的字符串。 但是，不同的存储提供程序可能会安惯例实施一些做法。

                                        例如，文件系统提供商在你的BLOB名称中使用目录分隔符（/）和文件扩展名（如果你的BLOB名称是images/common/x.png，那么它将保存为x.png在根容器文件夹内的images/common文件夹中）。
                    */

                    /*
                        四、类型化IBlobContainer 

                                类型化BLOB容器系统是一种在应用程序中"创建"和"管理" 多个容器的方法：

                                        ①、每个容器都单独存储。
                                                这意味着BLOB名称在一个容器中应该是唯一的，并且具有相同名称的两个BLOB可以存在于不同的容器中而不会相互影响。

                                        ②、每个容器都可以单独配置，因此每个容器可以根据你的配置使用不同的存储提供程序。


                                要创建类型化容器，你需要创建一个用 [BlobContainerName] 特性标准简单的类：

                                        using Volo.Abp.BlobStoring;

                                        namespace AbpDemo
                                        {
                                            [BlobContainerName("profile-pictures")]
                                            public class ProfilePictureContainer
                                            {
                                                
                                            }
                                        }

                                如果不使用[BlobContainerName] 特性，ABP使用类的全名 (带有命名空间)，但始终建议使用稳定且即使重命名类也不会更改的容器名称。
                                
                             
                                创建容器类后，你可以为你的容器类注入 IBlobContainer<T>

                                
                                eg:  应用程序服务保存和读取当前用户的个人资料图片

                                        [Authorize] // 授权过滤器
                                        public class ProfileAppService : ApplicationService
                                        {
                                            private readonly IBlobContainer<ProfilePictureContainer> _blobContainer;

                                            public ProfileAppService(IBlobContainer<ProfilePictureContainer> blobContainer)
                                            {
                                                _blobContainer = blobContainer; // 注入ProfilePictureContainer类型的IBlobContainer服务
                                            }

                                            // 保存BLOB对象
                                            public async Task SaveProfilePictureAsync(byte[] bytes)
                                            {
                                                var blobName = CurrentUser.GetId().ToString();
                                                await _blobContainer.SaveAsync(blobName, bytes);
                                            }
                                            
                                            // 读取BLOB对象
                                            public async Task<byte[]> GetProfilePictureAsync()
                                            {
                                                var blobName = CurrentUser.GetId().ToString();

                                                // 通过ProfilePictureContainer容器获取BLOB对象
                                                return await _blobContainer.GetAllBytesOrNullAsync(blobName);
                                            }
                                        }

                                IBlobContainer<T>具有与IBlobContainer相同的方法。

                                在开发“可重用模块”时始终使用"类型化BLOB容器"是一种很好的做法，因此，最终应用程序可以为你的容器配置提供程序，而不影响其他模块的容器。

                    */

                    /*
                        五、默认容器

                               如果你不使用泛型参数并直接注入IBlobContainer（如前所述），你将获得默认容器。 

                               注入默认容器的另一种方法是使用IBlobContainer<DefaultContainer>，它返回完全相同的容器。

                               默认容器的名称是 "default"。
                    */

                    /*
                        六、命名容器 NamedContainer
                                
                               类型化容器只是命名容器的快捷方式。 你可以注入并使用IBlobContainerFactory 按名称获取BLOB容器：

                                        public class ProfileAppService : ApplicationService
                                        {
                                            private readonly IBlobContainer _blobContainer;

                                            public ProfileAppService(IBlobContainerFactory blobContainerFactory)
                                            {
                                                _blobContainer = blobContainerFactory.Create("profile-pictures");
                                            }

                                            //...
                                        }
                    */

                    /*
                        七、 Blob容器工厂 IBlobContainerFactory
                                
                                IBlobContainerFactory是用于创建BLOB容器的服务。

                                eg： 给定名称创建容器：

                                        var blobContainer = blobContainerFactory.Create("profile-pictures");

                                eg: 给定类型创建容器：

                                        var blobContainer = blobContainerFactory.Create<ProfilePictureContainer>();
                                
                                你通常不需要使用 IBlobContainerFactory ,因为它是在IOC容器内部使用的，当你注入IBlobContainer<T> 其实就是在使用它。
                    */

                    /*
                        八、配置容器  Configuring The Containers

                                容器应在使用前进行配置。

                                最基本的配置是选择一个BLOB存储提供程序。

                                AbpBlobStoringOptions 是用于配置BLOB容器的选项类。 你可以在模块的ConfigureServices  方法中配置选项：

                                    
                                1、配置单个容器

                                            Configure<AbpBlobStoringOptions>(options=>{
                                                options.Containers.Configure<ProfilePictureConntainer>(container=>
                                                {

                                                })   
                                            });

                                        此示例配置ProfilePictureContainer容器，你还可以通过容器名称进行配置：

                                            Configure<AbpBlobStoringOptions>(options =>
                                            {
                                                options.Containers.Configure("profile-pictures", container =>
                                                {
                                                    //TODO...
                                                });
                                            });

                                2、配置默认容器
                                                
                                            Configure<AbpBlobStoringOptions>(options =>
                                            {
                                                options.Containers.ConfigureDefault(container =>
                                                {
                                                    //TODO...
                                                });
                                            });

                                        关于默认容器有一种特殊情况；如果没有为容器指定配置，它将回退到默认容器配置。

                                        这是为所有容器配置默认值并在需要时为特定容器专门化配置的好方法。


                                3、配置所有容器

                                        Configure<AbpBlobStoringOptions>(options =>
                                        {
                                            options.Containers.ConfigureAll((containerName, containerConfiguration) =>
                                            {
                                                //TODO...
                                            });
                                        });

                                        这是一种配置所有容器的方法。

                                        与配置默认容器的主要区别在于ConfigureAll会覆盖配置，即使它是专门用于特定容器的。
                    */

                    /*
                        九、多租户

                                如果你的应用程序设置为多租户，BLOB存储系统与多租户无缝协作。

                                所有提供商都将多租户作为标准功能实现。

                                他们将不同租户的BLOB相互隔离，因此他们只能访问自己的BLOB。

                                这意味着你可以对不同租户使用相同的BLOB名称。



                                如果你的应用程序是多租户，你可能希望单独控制容器的多租户行为。
                                例如，你可能希望为特定容器禁用多租户，因此其中的BLOB将对所有租户可用。 这是一种在所有租户之间共享BLOB的方法。

                                eg：   禁用特定容器的多租户：

                                        Configure<AbpBlobStoringOptions>(options =>
                                        {
                                            // 禁用特定类型容器的多租户支持
                                            options.Containers.Configure<ProfilePictureContainer>(container =>
                                            {
                                                container.IsMultiTenant = false; // 禁用多租户支持
                                            });
                                        });

                                如果你的应用程序不是多租户，不用担心，它会按预期工作。你不需要配置IsMultiTenant选项。
                    */

                    /*
                        十、扩展BLOB存储系统

                                大多数时候，除了创建自定义BLOB存储提供程序之外，你不需要自定义BLOB存储系统。

                                但是，如果需要，你可以替换任何服务（通过依赖注入注入）。

                                这里，还有一些上面没有提到的其他服务，但你可能想知道：

                                      1、IBlobProviderSelector用于通过容器名称获取IBlobProvider实例。
                                                默认实现（DefaultBlobProviderSelector）使用配置选择提供程序。

                                      2、IBlobContainerConfigurationProvider用于获取给定容器名称的BlobContainerConfiguration
                                                默认实现（DefaultBlobContainerConfigurationProvider）从上面解释的AbpBlobStoringOptions获取配置。

                    */

                    /*
                        十一、BLOB存储与文件管理系统的区别

                                     请注意，BLOB存储不是一个文件管理系统。

                                     它是一个用于保存、获取、删除已命名的Blob的低级系统。它不提供像目录这样的分层结构，这可能是你对典型文件系统的期望。

                                     如果你想创建文件夹并在文件夹之间移动文件、为文件分配权限并在用户之间共享文件，那么你需要在BLOB存储系统之上实现自己的应用程序。
                    */
        </script>
    </body>
</html>